package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Component;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author 应癫
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String, Object> map = new HashMap<>();  // 存储对象

    static {

        try {
            Reflections reflections = new Reflections(new ConfigurationBuilder()
                    .forPackages("com.lagou.edu") // 指定路径URL
//                .addScanners(new FieldAnnotationsScanner()) // 添加 属性注解扫描工具

            );
            // 反射出带有指定注解的类
            Set<Class<?>> classService = reflections.getTypesAnnotatedWith(Service.class);

            for (Class<?> class1 : classService) {

                //获取标注了@Service注解的属性
                Service serviceAnnotation = class1.getAnnotation(Service.class);
                //判断是否传参    传参使用参数中命名  不传参使用类的类名
                if (StringUtils.isEmpty(serviceAnnotation.value())) {
                    //由于getName获取的是全限定类名，所以要分割去掉前面包名部分
                    Class<?>[] interfaces = class1.getDeclaredConstructor().newInstance().getClass().getInterfaces();
                    String[] classRealArray = interfaces[0].getName().split("\\.");
                    map.put(classRealArray[classRealArray.length - 1], class1.getDeclaredConstructor().newInstance());
                } else {
                    map.put(serviceAnnotation.value(), class1.getDeclaredConstructor().newInstance());
                }
            }

            Set<Class<?>> classComponent = reflections.getTypesAnnotatedWith(Component.class);

            for (Class<?> class1 : classComponent) {

                //获取标注了@Component注解的属性
                Component componentAnnotation = class1.getAnnotation(Component.class);
                //判断是否传参    传参使用参数中命名  不传参使用类的类名
                if (StringUtils.isEmpty(componentAnnotation.value())) {
                    //由于getName获取的是全限定类名，所以要分割去掉前面包名部分
                    String[] classRealName = class1.getName().split("\\.");
                    map.put(classRealName[classRealName.length - 1], class1.getDeclaredConstructor().newInstance());
                } else {
                    map.put(componentAnnotation.value(), class1.getDeclaredConstructor().newInstance());
                }
            }

            Map<String, Object> map2 = new HashMap<>();

            for (String s : map.keySet()) {
                map2.put(s, map.get(s));
            }


            for (String className : map.keySet()) {

                Object classObject = map2.get(className);
                Field[] fields = classObject.getClass().getDeclaredFields();
                //遍历全部属性
                for (Field filed : fields) {
                    //获取标注了@Autowired注解的属性
                    Autowired autowiredAnnotation = filed.getAnnotation(Autowired.class);
//                System.out.println("autowiredAnnotation--" + autowiredAnnotation);
//                System.out.println("filed--" + filed);
//                System.out.println("autowiredAnnotation.value()--" + autowiredAnnotation.value());
                    if (null != autowiredAnnotation && StringUtils.isEmpty(autowiredAnnotation.value())) {
                        //修改属性的权限值
                        filed.setAccessible(true);
                        //获取属相类型
//                    System.out.println("filed----" + filed);
                        Class<?> type = filed.getType();
//                    System.out.println("type----" + type);
                        String[] names = type.getName().split("\\.");
                        String name = names[names.length - 1];
                        //属性赋值
                        filed.set(classObject, map2.get(name));
                    }else if(null != autowiredAnnotation){
                        filed.set(classObject, map2.get(autowiredAnnotation.value()));
                    }
                }
                map2.put(className, classObject);
            }

            for (String className : map.keySet()) {

                Object classObject = map2.get(className);
                //判断是否存在Transactional注解
                if (classObject.getClass().isAnnotationPresent(Transactional.class)) {

                    ProxyFactory proxyFactory = (ProxyFactory) map2.get("ProxyFactory");
                    //获取类实现的所有接口
                    //实现使用JDK
                    classObject = proxyFactory.getJdkProxy(classObject);
                    map2.put(className, classObject);
                }
            }
            map = map2;
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }

}
